﻿using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Reflection;

namespace Xoohoo.Validation
{
    internal static class ValidationAttributeCache
    {
        private static readonly ConcurrentDictionary<PropertyDescriptor, ReadOnlyCollection<ValidationAttribute>> _propertyValidationAttributeCache;
        private static readonly ConcurrentDictionary<MemberInfo, ReadOnlyCollection<ValidationAttribute>> _memberInfoValidationAttributeCache;
        private static readonly ConcurrentDictionary<Type, ReadOnlyCollection<ValidationAttribute>> _typeValidationAttributeCache;

        static ValidationAttributeCache()
        {
            _propertyValidationAttributeCache = new ConcurrentDictionary<PropertyDescriptor, ReadOnlyCollection<ValidationAttribute>>();
            _memberInfoValidationAttributeCache = new ConcurrentDictionary<MemberInfo, ReadOnlyCollection<ValidationAttribute>>();
            _typeValidationAttributeCache = new ConcurrentDictionary<Type, ReadOnlyCollection<ValidationAttribute>>();
        }
        public static ICollection<ValidationAttribute> GetPropertyValidationAttributes(PropertyDescriptor propertyDescriptor)
        {
            return _propertyValidationAttributeCache.GetOrAdd(propertyDescriptor, mi => new ReadOnlyCollection<ValidationAttribute>(propertyDescriptor.Attributes.OfType<ValidationAttribute>().ToList()));
        }
        public static ICollection<ValidationAttribute> GetMemberInfoValidationAttributes(MemberInfo memberInfo)
        {
            return GetAttributes<MemberInfo, ValidationAttribute>(_memberInfoValidationAttributeCache, memberInfo);
        }
        public static ICollection<ValidationAttribute> GetTypeValidationAttributes(Type type)
        {
            return GetAttributes<Type, ValidationAttribute>(_typeValidationAttributeCache, type);
        }
        private static ReadOnlyCollection<TAttribute> GetAttributes<TMemberInfo, TAttribute>(ConcurrentDictionary<TMemberInfo, ReadOnlyCollection<TAttribute>> lookup, TMemberInfo memberInfo)
            where TMemberInfo : MemberInfo
            where TAttribute : ValidationAttribute
        {
            return lookup.GetOrAdd(memberInfo, mi => new ReadOnlyCollection<TAttribute>((TAttribute[])memberInfo.GetCustomAttributes(typeof(TAttribute), true)));
        }
        
    }

}
